import React, { createRef, PureComponent } from 'react'
import ReactDOM from 'react-dom'
import { connect, history } from '@umijs/max'
import { Button, Collapse, Dropdown, Form, Input, Menu, message, Modal, Select } from 'antd'
import { CaretRightOutlined, ExclamationCircleFilled  } from '@ant-design/icons'
import { Addon, Graph, Path, ToolsView } from '@antv/x6'
import '@antv/x6-react-shape'
import { DispatchConf, OperateRecord, ViewDetail } from './page-components'
import { setCopy } from '@/components/CopyText'
import { DataDevLogger,ConsanguinityModal } from '@/components'
import { deleteNode } from '../../api'
import { DagreLayout } from '@antv/layout'

import { regExp } from '@/utils/regExp.js'
import Tools from '@/utils/Tools'
import styles from './index.less'
import {
  deleteRelation,
  detailTaskFlow,
  flowTaskStatus,
  queryDetailReq,
  saveNode,
  saveRelation,
  setScheduleStatus,
  startFlowTask,
  stopTask,
  taskLog,
  toolList,
  saveCoord
} from '../api'

const Bus = Tools.Bus
const { TextArea } = Input
const { Panel } = Collapse
const { Option } = Select

// form
const inlineFormItemLayout = {
  labelCol: {
    sm: { span: 5 },
  },
  wrapperCol: {
    sm: { span: 15 },
  },
}

const descRe = regExp.proName(0, 128)

const icon = {
  12: <span className={`${styles.offline_icon} ${styles.offline_icon_z}`}><i
    className="iconfont icon-xunijiedian" /></span>,
  13: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i
    className="iconfont icon-HiveSQL" /></span>,
  14: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i
    className="iconfont icon-MapRduce" /></span>,
  15: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i
    className="iconfont icon-Impala" /></span>,
  16: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i
    className="iconfont icon-Shell" /></span>,
  17: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i
    className="iconfont icon-Python2" /></span>,
  18: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i
    className="iconfont icon-Python3" /></span>,
  19: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i
    className="iconfont icon-Pyspark" /></span>,
  20: <span className={`${styles.offline_icon} ${styles.offline_icon_red}`}><i className="iconfont icon-lixiantongbu" /></span>,
  21: <span className={`${styles.offline_icon} ${styles.offline_icon_red}`}><i
    className="iconfont icon-jiekoucaiji" /></span>,
  22: <span className={`${styles.offline_icon} ${styles.offline_icon_blue}`}><i
    className="iconfont icon-shujuzhiliang1" /></span>,
}
const color = {
  12: 'node_z',
  13: 'node_green',
  14: 'node_green',
  15: 'node_green',
  16: 'node_green',
  17: 'node_green',
  18: 'node_green',
  19: 'node_green',
  20: 'node_red',
  21: 'node_red',
  22: 'node_blue',
}

const image = {
  3: <svg t="1650424548437" className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
    p-id="77657" width="20" height="20">
    <path
      d="M512 64a448 448 0 1 0 448 448A448 448 0 0 0 512 64z m0 810.666667a362.666667 362.666667 0 1 1 362.666667-362.666667 362.666667 362.666667 0 0 1-362.666667 362.666667z"
      p-id="77658" fill="#7fe312" />
    <path
      d="M725.333333 343.68L466.346667 602.666667 298.666667 434.986667l-60.373334 60.373333 167.68 167.68 60.373334 60.373333 60.373333-60.373333 258.986667-259.2L725.333333 343.68z"
      p-id="77659" fill="#7fe312" />
  </svg>,
  4: <svg t="1650424588552" className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
    p-id="77849" width="20" height="20">
    <path
      d="M724.266667 300.8l-150.826667 150.826667-150.826667-150.826667-60.373333 60.373333L513.066667 512l-150.826667 150.826667 60.373333 60.373333 150.826667-150.826667 150.826667 150.826667 60.373333-60.373333L633.813333 512l150.826667-150.826667-60.373333-60.373333z"
      p-id="77850" fill="#e01236" />
    <path
      d="M573.44 64a448 448 0 1 0 448 448 448 448 0 0 0-448-448z m0 810.666667a362.666667 362.666667 0 1 1 362.666667-362.666667 362.666667 362.666667 0 0 1-362.666667 362.666667z"
      p-id="77851" fill="#e01236" />
  </svg>,
  2: <svg t="1650424609124" className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
    p-id="78041" width="20" height="20">
    <path
      d="M945.706667 189.226667l-61.44 46.933333A462.506667 462.506667 0 0 0 522.666667 64 453.333333 453.333333 0 0 0 64 512a453.333333 453.333333 0 0 0 458.666667 448 458.666667 458.666667 0 0 0 431.146666-294.4 8.533333 8.533333 0 0 0-5.333333-11.093333l-61.866667-21.333334A8.746667 8.746667 0 0 0 874.666667 640c-1.92 5.333333-4.053333 10.666667-6.4 15.786667a365.653333 365.653333 0 0 1-78.933334 115.626666 375.68 375.68 0 0 1-119.253333 78.72 385.706667 385.706667 0 0 1-292.48 0 372.48 372.48 0 0 1-199.893333-195.413333 361.173333 361.173333 0 0 1 0-285.653333 368.64 368.64 0 0 1 80.426666-116.693334 379.093333 379.093333 0 0 1 119.466667-78.72 385.706667 385.706667 0 0 1 292.48 0 380.373333 380.373333 0 0 1 149.333333 112.213334l-65.706666 50.133333a8.533333 8.533333 0 0 0 3.2 15.146667l192 45.866666a8.746667 8.746667 0 0 0 10.88-8.32v-192a8.96 8.96 0 0 0-14.293334-6.613333z"
      p-id="78042" fill="#888585" />
  </svg>,
}

const lineColor = {
  0: '#0084FF',
  1: '#F76560',
  2: '#DCDEE1',
}

// 右击菜单
class ContextMenuTool extends ToolsView.ToolItem {
  render() {
    super.render()
    if (this.options.onHide) {
      this.options.onHide.call(this)
    }
    this.knob = ToolsView.createElement('div', false)
    this.knob.style.position = 'absolute'
    this.container.appendChild(this.knob)
    this.updatePosition(this.options)
    setTimeout(() => {
      this.toggleTooltip(true)
    })
    return this
  }

  toggleTooltip(visible) {
    ReactDOM.unmountComponentAtNode(this.knob)
    document.removeEventListener('mousedown', this.onMouseDown)

    if (visible) {
      ReactDOM.render(
        <Dropdown
          visible
          trigger={['contextMenu']}
          overlay={this.options.menu}
        >
          <a />
        </Dropdown>,
        this.knob,
      )
      document.addEventListener('mousedown', this.onMouseDown)
    }
  }

  updatePosition(pos) {
    const style = this.knob.style
    if (pos) {
      style.left = `${pos.x}px`
      style.top = `${pos.y}px`
    } else {
      style.left = '-1000px'
      style.top = '-1000px'
    }
  }

  onMouseDown = (e) => {
    setTimeout(() => {
      this.updatePosition()
      this.toggleTooltip(false)
      if (this.options.onHide) {
        this.options.onHide.call(this)
      }
    }, 200)
  };
}

ContextMenuTool.config({
  tagName: 'div',
  isSVGElement: false,
})

// 连线右击弹框
Graph.registerEdgeTool('contextmenu', ContextMenuTool, true)
// 节点右击弹框
Graph.registerNodeTool('contextmenu', ContextMenuTool, true)

// 节点样式
class AlgoNode extends React.Component {
  shouldComponentUpdate() {
    const { node } = this.props
    if (node) {
      if (node.hasChanged('data')) {
        return true
      }
    }
    return false
  }

  render() {
    const { node } = this.props
    const data = node?.getData()
    const { label, status = '' } = data
    return (
      <div className={`node ${styles.node} ${styles[color[data.nodeType]]} ${color[data.nodeType]}`}>
        {icon[data.nodeType]}
        <span className={`${styles.label} ${styles.text_overflow_single}`} title={label}>{label}</span>
        <span className={`${styles.status} ${styles[status]}`}>
          {status == 3 && image[status]}
          {status == 4 && image[status]}
          {status == 2 && image[status]}
        </span>
      </div>
    )
  }
}

@connect(({ flowDev }) => ({ ...flowDev }))
export default class Flow extends PureComponent {
  constructor(props) {
    super(props)
    this.state = {
      isbleRubberband: false,
      loggerList: [],
      allComponents: [],
      scheduleStatus: 0,
      data: [],
      isShowOperateBtn: false,
      selectedBtn: null,
      isRun: false,
      runState: 0,
      currentTargetNode: {},
      resultss: [
        {
          result: '运行日志',
          value: ['暂无运行'],
          key: 'logger',
          name: '运行日志',
        },
      ],
      activeKey: '0',
      xxlJobId: '',
      isShowConsanguinity: false,
    }
    this.viewDetailRef = createRef()
    this.operateRecordRef = createRef()
    this.dispatchConfRef = createRef()
    this.nodeMenu = (item) => {
      const node = item.getData()
      if (node.nodeType == 12) {
        // return (
        //   <Menu>
        //     <Menu.Item>
        //       修改
        //     </Menu.Item>
        //   </Menu>
        // )
      }
      return (
        <Menu>
          <Menu.Item onClick={() => {
            const modal = Modal.confirm({
              title: '确认要删除这个任务吗？',
              icon: <ExclamationCircleFilled />,
              content: '删除后数据将无法恢复，请谨慎操作',
              okText: '删除',
              cancelText: '取消',
              okButtonProps: {
                danger: true,
              },
              onOk: () => {
                const { taskNode } = this.props
                return deleteNode({ id: node.id, taskFlowId: taskNode.id }).then(
                  (res) => {
                    if (res.status == 200) {
                      this.graph.removeNode(node.id)
                      Bus.emit('getListAll')
                      // modal.destroy();
                    } else {
                      message.error(res.msg)
                    }
                  }
                )
                // this.props.dispatch({
                //   type: 'flowDev/deleteNode',
                //   params: { id: node.id, taskFlowId: taskNode.id },
                //   cb: (res) => {
                //     if (res.status == 200) {
                //       this.graph.removeNode(node.id)
                //       Bus.emit('getListAll')
                //       modal.destroy();
                //     } else {
                //       message.error(res.msg)
                //     }
                //   },
                // })
              },
            })
          }}
          >
            删除
          </Menu.Item>
          <Menu.Item onClick={() => {
            this.queryDetailReq(node.id)
          }}
          >
            修改
          </Menu.Item>
          <Menu.Item onClick={() => {
            setCopy(node.label)
          }}
          >
            名称复制
          </Menu.Item>
        </Menu>
      )
    }
    this.edgeMenu = (item) => {
      const status = item.store.data.status ? String(item.store.data.status) : '0'
      const source = item.getSource().cell
      const target = item.getTarget().cell
      return (
        <Menu
          selectedKeys={[status]}
          onClick={(obj) => {
            if (obj.key == '0' || obj.key == '1' || obj.key == '2') {
              this.saveRelation(source, target, obj.key)
            }
            if (obj.key == '3') {
              this.deleteRelation(source, target, item.id)
            }
          }}
        >
          <Menu.Item key={0}>
            成功后执行下游节点
          </Menu.Item>
          <Menu.Item key={1}>
            失败后执行下游节点
          </Menu.Item>
          <Menu.Item key={2}>
            始终执行下游节点
          </Menu.Item>
          <Menu.Item key={3}>
            删除
          </Menu.Item>
        </Menu>
      )
    }
    this.cataNodeForm = React.createRef()
    this.time = null
    this.graph = null
  }

  componentWillMount() {
    // 节点、锚点
    Graph.registerNode(
      'node',
      {
        inherit: 'react-shape',
        width: 220,
        height: 42,
        component: <AlgoNode />,
        ports: {
          groups: {
            in: {
              position: 'top',
              attrs: {
                circle: {
                  r: 4,
                  magnet: true,
                  stroke: '#C2C8D5',
                  strokeWidth: 1,
                  fill: '#fff',
                },
              },
            },
            out: {
              position: 'bottom',
              attrs: {
                circle: {
                  r: 4,
                  magnet: true,
                  stroke: '#C2C8D5',
                  strokeWidth: 1,
                  fill: '#fff',
                },
              },
            },
          },
        },
      },
      true,
    )

    // 线
    Graph.registerEdge(
      'edge',
      {
        inherit: 'edge',
        attrs: {
          line: {
            stroke: '#C2C8D5',
            strokeWidth: 1,
            targetMarker: {
              args: {
                size: 8,
              },
              name: 'classic',
            }, // 箭头
          },
        },
      },
      true,
    )

    Graph.registerConnector(
      'algo-connector-flow',
      (s, e) => {
        const offset = 4
        const deltaY = Math.abs(e.y - s.y)
        const control = Math.floor((deltaY / 3) * 2)

        const v1 = { x: s.x, y: s.y + offset + control }
        const v2 = { x: e.x, y: e.y - offset - control }

        return Path.normalize(
          `M ${s.x} ${s.y}
       L ${s.x} ${s.y + offset}
       C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
       L ${e.x} ${e.y}
      `,
        )
      },
      true,
    )
  }

  componentDidMount() {
    this.toolList()
    this.init()
    this.detailTaskFlow()
    Bus.addListener('refreshFlow', this.detailTaskFlow)
  }

  componentWillUnmount() {
    // 卸载画布
    this.time && clearTimeout(this.time)
    this.graph && this.graph.dispose()
    Bus.removeListener('refreshFlow', this.detailTaskFlow)
  }

  toolList = () => {
    toolList().then((res) => {
      if (res.data) {
        this.setState({
          allComponents: [
            {
              label: '数据集成',
              id: '3',
              children: res.data.offlineSync,
            },
            {
              label: '数据开发',
              id: '1',
              children: res.data.datadev,
            },
            {
              label: '数据质量',
              id: '2',
              children: res.data.dataQuality,
            },
          ],
        })
      }
    })
  }

  detailTaskFlow = () => {
    const { taskNode } = this.props
    detailTaskFlow({
      id: taskNode.id,
    }).then((res) => {
      if (res.status == 200) {
        const data = []
        const nodes = res.data && res.data.nodes || []
        const edges = res.data && res.data.edges || []
        nodes.map((item) => {
          if (item.nodeType == 12) {
            data.push(
              {
                id: `${item.id}`,
                shape: 'node',
                x: Number(item.x),
                y: Number(item.y),
                data: {
                  label: item.nodeName,
                  status: '',
                  id: item.id,
                  nodeType: item.nodeType,
                },
                ports: [
                  {
                    id: `${item.id}_out`,
                    group: 'out',
                  },
                ],
              },
            )
          } else {
            data.push(
              {
                id: `${item.id}`,
                shape: 'node',
                x: Number(item.x),
                y: Number(item.y),
                data: {
                  label: item.nodeName,
                  status: '',
                  id: item.id,
                  nodeType: item.nodeType,
                  apiType: item.apiType,
                },
                ports: [
                  {
                    id: `${item.id}_in`,
                    group: 'in',
                  },
                  {
                    id: `${item.id}_out`,
                    group: 'out',
                  },
                ],
              },
            )
          }
        })
        edges.map((item) => {
          data.push(
            {
              id: `${item.from}_${item.to}`,
              shape: 'edge',
              status: item.status,
              source: {
                cell: `${item.from}`,
                port: `${item.from}_out`,
              },
              target: {
                cell: `${item.to}`,
                port: `${item.to}_in`,
              },
              attrs: {
                line: {
                  stroke: lineColor[item.status],
                },
              },
              zIndex: 0,
            },
          )
        })
        this.setState({
          data,
          scheduleStatus: res.data.isLock,
          xxlJobId: res.data.xxlJobId
        })
        this.initNodeEdge(data)
      } else {
        message.error(res.msg)
      }
    })
  }

  init = () => {
    const { taskNode, themeValue } = this.props
    this.graph = new Graph({
      container: document.getElementById(`${taskNode.id}`),
      snapline: true, // 对齐线
      panning: {
        enabled: true,
        // eventTypes: ['leftMouseDown', 'mouseWheel'], // 是否加左右上下滚动条
      },
      mousewheel: {
        enabled: true,
        // modifiers: 'ctrl', // 缩放是否ctrl+滚轮
        factor: 1.1,
        // maxScale: 1.5, // 最大缩放
        // minScale: 0.1, // 最小缩放
      },
      grid: {
        size: 15, // 网格大小 10px
        type: 'doubleMesh', // 指定网格类型
        visible: true, // 绘制网格，默认绘制 dot 类型网格
        args: [
          {
            color: themeValue === 'dark' ? 'rgba(238,238,238,.15)' : '#eee', // 主网格线颜色
            thickness: 1, // 主网格线宽度
          },
          {
            color: themeValue === 'dark' ? 'rgba(238,238,238,.15)' : '#eee', //'#ddd', // 次网格线颜色
            thickness: 1, // 次网格线宽度
            factor: 4, // 主次网格线间隔
          },
        ],
      },
      highlighting: {
        magnetAdsorbed: {
          name: 'stroke',
          args: {
            attrs: {
              fill: '#fff',
              stroke: '#31d0c6',
              strokeWidth: 1,
            },
          },
        },
      },
      connecting: {
        snap: {
          radius: 20,
        },
        allowBlank: false,
        allowLoop: false,
        allowEdge: false,
        highlight: true,
        allowMulti: 'withPort',
        allowNode: false,
        connector: 'algo-connector-flow',
        connectionPoint: 'anchor',
        anchor: 'center',
        validateMagnet(e) {
          return e.magnet.getAttribute('port-group') !== 'in'
        },
        validateEdge({ edge, type }) {
          return edge.getTarget().port.indexOf('out') == -1
        },
        createEdge: () => this.graph.createEdge({
          shape: 'edge',
          attrs: {
            line: {
              strokeDasharray: '5 5',
            },
          },
          zIndex: -1,
        }),
      },
      // autoResize: true, //是否自动扩充/缩小画布 移动节点/边时将自动计算需要的画布大小，当超出当前画布大小时，按照 pageWidth 和  pageHeight 自动扩充画布。反之，则自动缩小画布。
      selecting: {
        enabled: true,
        rubberband: false,
        multiple: true,
        strict: true,
        showNodeSelectionBox: false,
        selectNodeOnMoved: false,
      },
    })

    // 节点右击事件
    this.graph.on('node:contextmenu', ({ cell, e }) => {
      const p = this.graph.clientToGraph(e.clientX, e.clientY)
      if (
        cell
        && cell.store
        && cell.store.data
      ) {
        cell.addTools([
          {
            name: 'contextmenu',
            args: {
              menu: this.nodeMenu(cell),
              x: p.x,
              y: p.y,
              onHide() {
                this.cell.removeTools()
              },
            },
          },
        ])
      }
    })

    // 线右击事件
    this.graph.on('edge:contextmenu', ({ cell, e }) => {
      const p = this.graph.clientToGraph(e.clientX, e.clientY)
      if (
        cell
        && cell.store
        && cell.store.data
      ) {
        cell.addTools([
          {
            name: 'contextmenu',
            args: {
              menu: this.edgeMenu(cell),
              x: p.x,
              y: p.y,
              onHide() {
                this.cell.removeTools()
              },
            },
          },
        ])
      }
    })

    // 线点击事件
    this.graph.on('edge:click', ({ cell, e }) => {
      console.log(cell.store.data)
    })

    // 画布空白处点击事件
    this.graph.on('blank:click', ({ node }) => {
      this.dispatchConfRef?.current?.toggleDispatchConf(false, 'clear')
      const { selectedBtn } = this.state
      const { activeKey, tasks } = this.props
      const filterNode = tasks?.filter(item => item.id == activeKey) || []
      const currentTargetNode = filterNode?.[0] || {}
      this.setState({
        currentTargetNode,
        isShowOperateBtn: false,
        selectedBtn: selectedBtn == 'conf' ? null : selectedBtn,
      })
    })

    // 节点点击事件
    this.graph.on('node:click', ({ node }) => {
      const data = node?.getData() || {}
      const { nodeType } = data
      if (nodeType == 12) {
        this.setState({
          isShowOperateBtn: true, // 开始节点，展示 调度配置按钮
          currentTargetNode: data,
        })
      } else {
        this.dispatchConfRef?.current?.toggleDispatchConf(false, 'clear')
        const { selectedBtn } = this.state
        this.setState({
          isShowOperateBtn: false,
          currentTargetNode: data,
          selectedBtn: selectedBtn == 'conf' ? null : selectedBtn,
        })
      }
    })

    // 节点双击事件
    this.graph.on('node:dblclick', ({ node }) => {
      const data = node.getData()
      if (data.nodeType != 12) {
        const targetKey = data.id
        this.props.dispatch({
          type: 'flowDev/taskTabsHandle',
          params: {
            id: targetKey,
          },
        })
        this.props.dispatch({
          type: 'flowDev/setSelectedKey',
          params: {
            selectedKeys: targetKey,
            treeCurrentTargetNode: data,
          },
          cb: () => {
            Bus.emit('editorLayout', targetKey)
          },
        })
      }
    })

    // 移动节点结束
    this.graph.on('node:moved', ({ node }) => {
      const data = node.getData()
      const { x, y } = node.position()
      this.saveNode({
        id: taskNode.id,
        x,
        y,
        nodeType: data.nodeType,
        nodeName: data.label,
        subTaskId: data.id,
      })
    })

    // 监听连线完成
    this.graph.on('edge:connected', ({ isNew, edge }) => {
      if (isNew) {
        const source = edge.getSource().cell
        const target = edge.getTarget().cell
        this.saveRelation(source, target)
      }
      edge.attr({
        line: {
          strokeDasharray: '',
          stroke: '#0084FF',
        },
      })
    })

    // 数据发生变化
    this.graph.on('node:change:data', ({ node }) => {
      const edges = this.graph.getIncomingEdges(node)
      const { status } = node ? node.getData() : {}
      edges?.forEach((edge) => {
        if (status == 2) {
          edge.attr('line/strokeDasharray', 5)
          // eslint-disable-next-line prefer-template
          edge.attr('line/style/animation', styles.running_line + ' 30s infinite linear')
          edge.attr({
            line: {
              stroke: '#0084ff',
            },
          })
        } else {
          edge.attr('line/strokeDasharray', '')
          edge.attr('line/style/animation', '')
          edge.attr({
            line: {
              stroke: lineColor[edge.store.data.status],
            },
          })
        }
      })
    })
  }

  // 删除线
  deleteRelation = (upNodeId, downNodeId, id) => {
    const { taskNode } = this.props
    deleteRelation({ upNodeId, downNodeId, taskFlowNodeId: taskNode.id }).then((res) => {
      if (res.status == 200) {
        this.graph.removeEdge(id)
      } else {
        message.error(res.msg)
      }
    })
  }

  // 移动&&创建节点
  saveNode = (data, change) => {
    saveNode({ ...data }).then((res) => {
      if (res.status == 200) {
        if (!data.subTaskId) {
          Bus.emit('getListAll')
          this.detailTaskFlow()
        }
        if (this.state.isShowFiles) {
          this.setState({
            isShowFiles: false,
          })
          const node = this.graph.getCellById(data.subTaskId)
          const item = node && node.getData()
          node && node.setData({
            ...item,
            label: data.nodeName,
          })
          Bus.emit('getListAll')

          const newData = node?.getData() || {}
          if (newData?.nodeType == 12) {
            this.setState({
              isShowOperateBtn: true, // 开始节点，展示 调度配置按钮
              currentTargetNode: newData,
            })
          } else {
            this.dispatchConfRef?.current?.toggleDispatchConf(false, 'clear')
            const { selectedBtn } = this.state
            this.setState({
              isShowOperateBtn: false,
              currentTargetNode: newData,
              selectedBtn: selectedBtn == 'conf' ? null : selectedBtn,
            })
          }
        }
      } else {
        if (!change) {
          this.initNodeEdge(this.state.data)
        }
        message.error(res.msg)
      }
    })
  }

  saveRelation = (source, target, status) => {
    saveRelation({
      upNodeId: source,
      downNodeId: target,
      status: status || status == 0 ? status : 0,
      taskFlowNodeId: this.props.taskNode.id,
    }).then((res) => {
      if (res.status != 200) {
        message.error(res.msg)
        this.initNodeEdge(this.state.data)
      } else if (status) {
        this.detailTaskFlow()
      }
    })
  }

  // 一键布局
  onLayout = () => {
    const nodes = this.graph.getNodes()
    const edges = this.graph.getEdges()
    const _data = {
      nodes: nodes.map((node) =>{
        return {
          id: String(node.id),
          shape: 'node',
          data:node.getData(),
          ports: node.port.ports,
        }
      }),
      edges: edges.map((edge) =>{
        return {
          id: edge.id,
          shape: 'edge',
          status: edge.store.data.status,
          source: edge.getSource(),
          target: edge.getTarget(),
          attrs: edge.getAttrs().line,
          zIndex: 0,
        }
      }),
    }
    const model = this.dagreLayout.layout(_data)
    if(model?.nodes?.length) {
      const { taskNode } = this.props
      saveCoord({
        taskFlowNodeId: taskNode.id,
        coordList: model.nodes.map((node)=>{
          return {
            "nodeId": node.id,
            "x": node.x + "",
            "y": node.y + ""
          }
        })
      }).then(
        (res) =>{
          message.success('布局成功')
        }
      )
    }
    this.graph.fromJSON(model)
  }

  // 查看血缘
  onConsanguinity = () => {
    this.setState({ isShowConsanguinity: true })
  }

  // 初始化节点/边
  initNodeEdge = (data) => {
    const cells = []
    data.forEach((item) => {
      if (item.shape == 'node') {
        cells.push(this.graph.createNode(item))
      } else {
        cells.push(this.graph.createEdge(item))
      }
    })
    this.dagreLayout = new DagreLayout({
      type: 'dagre',
      rankdir: 'TB',
      ranksep: 40,
      nodesep: 80,
      begin: [440,250]
    })
    this.graph.resetCells(cells)
  }

  // 显示节点状态
  showNodeStatus = async (statusList) => {
    const status1 = statusList.shift()
    status1?.forEach((item) => {
      const { nodeId, taskStatus } = item
      const node = this.graph.getCellById(nodeId)
      const data = node.getData()
      node && node.setData({
        ...data,
        status: taskStatus,
      })
    })
  }

  rubberband = () => {
    if (!this.graph) return
    if (this.graph.isRubberbandEnabled()) {
      this.graph.enablePanning() // 开启画布拖拽
      this.graph.disableRubberband() // 关闭框选
      this.setState({
        isbleRubberband: false,
      })
    } else {
      this.setState({
        isbleRubberband: true,
      })
      this.graph.disablePanning() // 禁止画布拖拽
      this.graph.enableRubberband() // 开启框选
    }
  }

  // 缩放画布
  zoom = (factor) => {
    if (!this.graph) return
    if (typeof factor == 'number') {
      this.graph?.zoom(factor)
    } else if (factor == 'fit') {
      this.graph?.zoomToFit({ padding: 100 })
    } else if (factor == 'real') {
      this.graph?.scale(1)
      this.graph?.centerContent()
    }
  }

  /*
    放大、缩小、实际尺寸、适应画布
    action: 'in' | 'out' | 'fit' | 'real'
  */
  onHandleSideToolbar = (action) => {
    // 确保画布已渲染
    switch (action) {
      case 'in':
        this.zoom(0.1)
        break
      case 'out':
        this.zoom(-0.1)
        break
      case 'fit':
        this.zoom('fit')
        break
      case 'real':
        this.zoom('real')
        break
      default:
    }
  }

  // 拖动添加节点
  AddNode = (item, e) => {
    const dnd = new Addon.Dnd({
      target: this.graph,
      getDragNode: (nodeItem) => this.graph.createNode({
        shape: 'react-shape',
        width: 220,
        height: 42,
        nodeItem,
        component: () => {
          const label = nodeItem.text
          return (
            <div className={`node ${styles.node} ${styles[color[nodeItem.nodeType]]} ${color[nodeItem.nodeType]}`}>
              {icon[nodeItem.nodeType]}
              <span className={`${styles.label} ${styles.text_overflow_single}`} title={label}>{label}</span>
            </div>
          )
        },
        ports: {
          groups: {
            in: {
              position: 'top',
              attrs: {
                circle: {
                  r: 4,
                  magnet: true,
                  stroke: '#C2C8D5',
                  strokeWidth: 1,
                  fill: '#fff',
                },
              },
            },
            out: {
              position: 'bottom',
              attrs: {
                circle: {
                  r: 4,
                  magnet: true,
                  stroke: '#C2C8D5',
                  strokeWidth: 1,
                  fill: '#fff',
                },
              },
            },
          },
        },
      }),
      getDropNode: (nodeItem) => nodeItem.clone(),
      validateNode: (nodeItem, node) => {
        const { x, y } = nodeItem.position()
        this.setState({
          isShowFiles: true,
          title: null,
          subTaskId: null,
          nodeItem: {
            nodeType: node.sourceNode.nodeType,
            x,
            y,
          },
        })
        return false
      },
    })
    dnd.start(item, e)
  }

  saveNodeFn = () => {
    const { nodeItem, subTaskId } = this.state
    const { taskNode } = this.props
    this.cataNodeForm.current.validateFields().then(values => {
      this.saveNode({
        ...nodeItem,
        id: taskNode.id,
        nodeName: values.name,
        remark: values.remark,
        subTaskId: subTaskId || null,
        apiType: values.apiType || null,
      }, true)
    })
  }

  // eslint-disable-next-line react/no-unused-class-component-methods
  toggleViewDetail = () => {
    this.operateRecordRef?.current?.toggleOperateRecord(false)
    this.dispatchConfRef?.current?.toggleDispatchConf(false)
    this.viewDetailRef?.current?.toggleViewDetail()
    this.setState({
      selectedBtn: 'detail',
    })
  };

  toggleOperateRecord = () => {
    this.dispatchConfRef?.current?.toggleDispatchConf(false)
    this.viewDetailRef?.current?.toggleViewDetail(false)
    this.operateRecordRef?.current?.toggleOperateRecord()
    this.setState({
      selectedBtn: 'record',
    })
  }

  toggleDispatchConf = () => {
    this.viewDetailRef?.current?.toggleViewDetail(false)
    this.operateRecordRef?.current?.toggleOperateRecord(false)
    this.dispatchConfRef?.current?.toggleDispatchConf()
    this.setState({
      selectedBtn: 'conf',
    })
  }

  // 节点详情
  queryDetailReq = (id) => {
    queryDetailReq({ nodeId: id }).then((data) => {
      const node = this.graph.getCellById(id)
      const item = node.getData()
      const { x, y } = node.position()
      this.setState({
        isShowFiles: true,
        title: '修改节点',
        subTaskId: id,
        nodeItem: {
          ...item,
          x,
          y,
        },
      }, () => {
        setTimeout(() => {
          this.cataNodeForm && this.cataNodeForm.current && this.cataNodeForm.current.setFieldsValue({
            name: data.name,
            remark: data.remark,
            apiType: String(data?.apiType),
          })
        }, 1000)
      })
    })
  }

  // 任务开始
  startFlowTask = () => {
    if (this.state.runState == 1) return
    const { taskNode } = this.props
    startFlowTask({
      nodeId: taskNode.id,
    }).then((res) => {
      if (res.status == 200) {
        message.success(res.msg)
        this.setState({
          jobId: res.data,
          runState: 1,
          loggerList: [res.msg],
        })
        Bus.emit('iconUpFn', this.props.taskNode.id)
        this.taskLog(res.data)
      } else {
        message.error(res.msg)
      }
    })
  }

  // 任务日志
  taskLog = (jobId, offset) => {
    taskLog({
      jobId,
      offset: offset || offset == 0 ? offset : 0,
    }).then((res) => {
      if (res.status == 200) {
        this.flowTaskStatus(jobId)
        clearTimeout(this.time)
        const { logContent, logEnd, results } = res.data
        const { resultss } = this.state

        let { loggerList } = this.state
        if (logContent && logContent.length) {
          loggerList = loggerList.concat(logContent)
        }
        resultss[0].value = loggerList || []

        const arr = this.state.resultss
        let newResults = [...results]

        if (newResults && newResults.length) {
          newResults.map((obj) => {
            obj.jobId = jobId
          })
          newResults = arr.concat(newResults)
        }

        newResults && newResults.length
          ? newResults.map((item, k) => {
            item.name ? null : (item.name = `结果[${k}]`)
          })
          : null
        this.setState({
          loggerList,
          resultss: newResults && newResults.length ? newResults : arr,
        }, () => {
          this.time = setTimeout(() => {
            this.taskLog(jobId, res.data.offset)
          }, 2000)
        })
        if (logEnd) {
          clearTimeout(this.time)
          this.setState({
            runState: 0,
          })
        }
      } else {
        clearTimeout(this.time)
        this.setState({
          runState: 0,
        })
        message.error(res.msg)
      }
    })
  }

  // 结束任务
  stopTask = () => {
    if (this.state.runState == 0) return
    const { jobId } = this.state
    stopTask({ jobId }).then((res) => {
      if (res.status == 200) {
        message.success(res.msg)
        clearTimeout(this.time)
        this.setState({
          runState: 0,
        })
      } else {
        message.error(res.msg)
      }
      this.flowTaskStatus(jobId)
    })
  }

  // 工作流运行状态
  flowTaskStatus = (jobId) => {
    flowTaskStatus({ jobId }).then((res) => {
      if (res.status == 200) {
        this.showNodeStatus([res.data])
      }
    })
  }

  setScheduleStatus = (scheduleStatus) => {
    const { taskNode } = this.props
    this.setState({
      lodings: true,
    })
    setScheduleStatus({ taskFlowNodeId: taskNode.id, status: scheduleStatus }).then((res) => {
      if (res.status == 200) {
        this.setState({
          scheduleStatus,
        })
        message.success(res.msg)
        Bus.emit('getListAll')
      } else {
        message.error(res.msg)
      }
      this.setState({
        lodings: false,
      })
    })
  }

  activeKeyonChange = (activeKey) => {
    this.setState({ activeKey })
  };

  render() {
    const { taskNode } = this.props
    const {
      isbleRubberband,
      isShowOperateBtn,
      selectedBtn,
      currentTargetNode,
      resultss,
      loggerList,
      isRun,
      nodeItem,
      runState,
      allComponents,
      scheduleStatus,
      xxlJobId,
    } = this.state
    return (
      <div className={styles.flow_container}>
        <div className={styles.flow_id} id={`${taskNode.id}`} style={{ flex: '1' }} />
        <div className={styles.flow_panel_header}>
          <dl
            onClick={() => {
              this.startFlowTask()
            }}
            className={`${runState == 1 && styles.disable}`}
          >
            <dt><i className="iconfont icon-yunhang" /></dt>
            <dd>运行</dd>
          </dl>
          <dl
            onClick={() => {
              this.stopTask()
            }}
            className={`${runState == 0 && styles.disable}`}
          >
            <dt><i className="iconfont icon-tingzhi" /></dt>
            <dd>停止</dd>
          </dl>
          <dl onClick={this.detailTaskFlow}>
            <dt><i className="iconfont icon-shuaxin" /></dt>
            <dd>刷新</dd>
          </dl>
          <dl onClick={() => {
            this.onHandleSideToolbar('in')
          }}
          >
            <dt><i className="iconfont icon-fangda" /></dt>
            <dd>放大</dd>
          </dl>
          <dl onClick={() => {
            this.onHandleSideToolbar('out')
          }}
          >
            <dt><i className="iconfont icon-suoxiao" /></dt>
            <dd>缩小</dd>
          </dl>
          <dl onClick={this.rubberband} className={isbleRubberband ? styles.active_icon : ''}>
            <dt><i className="iconfont icon-yunhang" /></dt>
            <dd>框选节点</dd>
          </dl>
          <dl onClick={() => {
            this.onHandleSideToolbar('real')
          }}
          >
            <dt><i className="iconfont icon-yunhang" /></dt>
            <dd>实际尺寸</dd>
          </dl>
          <dl onClick={() => {
            this.onHandleSideToolbar('fit')
          }}
          >
            <dt><i className="iconfont icon-yunhang" /></dt>
            <dd>适应画布</dd>
          </dl>
          <dl onClick={() => {
            this.onLayout()
          }}
          >
            <dt><i className="iconfont icon-yunhang" /></dt>
            <dd>自动布局</dd>
          </dl>
          <dl onClick={() => {
            this.onConsanguinity()
          }}
          >
            <dt><i className="iconfont icon-zhexiantu-xianxing" /></dt>
            <dd>血缘分析</dd>
          </dl>
          <span className={styles.flow_panel_button} style={{ float: 'right' }}>
            {this.state.scheduleStatus == 1 ? (
              <Button
                loading={this.state.lodings}
                onClick={() => {
                  this.setScheduleStatus(0)
                }}
              >上线
              </Button>
            ) : (
              <Button
                loading={this.state.lodings}
                onClick={() => {
                  this.setScheduleStatus(1)
                }}
              >冻结
              </Button>
            )}
            <Button
              type="primary"
              style={{ marginLeft: '.14rem' }}
              onClick={() => {
                const { taskNode, dispatch } = this.props
                const params = { searchValue: taskNode?.name }
                dispatch({
                  type: 'operation/saveSearchDefault',
                  params: {
                    ...params,
                    activeTabKey: '2',
                  },
                })
                history.push('/data-development/offline/task-operation')
              }}
            >运维
            </Button>
          </span>
        </div>
        <div className={styles.flow_panel}>
          <div className={styles.title}>
            开发组件
          </div>
          <div className={styles.center}>
            <Collapse
              ghost
              defaultActiveKey={['1', '2', '3']}
              expandIcon={({ isActive }) => <CaretRightOutlined style={{ color: 'rgba(0, 0, 0, 0.45)' }}
                rotate={isActive ? 90 : 0} />}
            >
              {allComponents.map((component) => (
                <Panel header={<span style={{ color: 'rgba(0, 0, 0, 0.45)' }}>{component.label}</span>}
                  key={component.id}>
                  {/*  渲染可以拖拽的gg-editor节点，item.model是节点渲染所需要的数据  */}
                  {component.children.map((item, k) => (
                    <div
                      key={k}
                      onMouseDown={(e) => {
                        this.AddNode(item, e)
                      }}
                      className={styles.panel}
                    >{icon[item.nodeType]} {item.text}
                    </div>
                  ))}
                </Panel>
              ))}
            </Collapse>
          </div>
        </div>
        <div className={styles.flow_right}>
          <span className={`${selectedBtn == 'detail' ? styles.on : ''}`}
            onClick={this.toggleViewDetail}>节点详情</span>
          {isShowOperateBtn && <span className={`${selectedBtn == 'conf' ? styles.on : ''}`}
            onClick={this.toggleDispatchConf}>调度配置</span>}
          <span className={`${selectedBtn == 'record' ? styles.on : ''}`}
            onClick={this.toggleOperateRecord}>操作记录</span>
        </div>
        <ViewDetail ref={this.viewDetailRef} currentTargetNode={currentTargetNode} taskNode={this.props?.taskNode} />
        <DispatchConf ref={this.dispatchConfRef} currentTargetNode={currentTargetNode}
          detailTaskFlow={this.detailTaskFlow} scheduleStatus={scheduleStatus} xxlJobId={xxlJobId} />
        <OperateRecord ref={this.operateRecordRef} currentTargetNode={currentTargetNode} />
        <DataDevLogger
          list={loggerList || []}
          results={resultss}
          jobId={this.state.jobId}
          className={styles.flow_log}
          style="flow"
          activeKey={this.state.activeKey}
          activeKeyonChange={this.activeKeyonChange}
          taskId={taskNode.id}
        />
        <Modal
          destroyOnClose
          title={this.state.title ? this.state.title : '新建节点'}
          visible={this.state.isShowFiles}
          confirmLoading={this.state.confirmLoading}
          cancelText="取消"
          okText="保存"
          onOk={this.saveNodeFn}
          onCancel={() => {
            this.setState({
              isShowFiles: false,
            })
          }}
        >
          <Form {...inlineFormItemLayout} ref={this.cataNodeForm}>
            <Form.Item
              rules={[
                { required: true, message: '请输入节点名称' },
                {
                  required: false,
                  pattern: new RegExp(regExp.name(2, 64).reg, 'g'),
                  message: regExp.name(2, 64).text,
                },
              ]}
              name="name"
              label="节点名称"
              labelAlign="right"
            >
              <Input placeholder="请输入节点名称" />
            </Form.Item>
            {
              nodeItem?.nodeType == 21 && (
                <Form.Item
                  rules={[
                    { required: true, message: '请选择接口采集类型' },
                  ]}
                  name="apiType"
                  label="接口采集类型"
                >
                  <Select>
                    <Option key={0}>Http/Https</Option>
                    <Option key={1}>WebService</Option>
                  </Select>
                </Form.Item>
              )
            }
            <Form.Item
              label="描述"
              labelAlign="right"
              name="remark"
              rules={[
                { required: false },
                {
                  pattern: new RegExp(descRe.reg, 'g'),
                  message: descRe.text,
                },
              ]}
            >
              <TextArea
                placeholder="请输入描述"
                autoSize={{ minRows: 3, maxRows: 6 }}
              />
            </Form.Item>
          </Form>
        </Modal>
        <ConsanguinityModal visible={this.state.isShowConsanguinity} onClose={() => {this.setState({ isShowConsanguinity: false })}} obj={{taskFlowId: taskNode.id}}/>
      </div>
    )
  }
}
